class Collection {
    constructor(name) {
        this.name = name;
        this.list = [];
        this.changeCallbackList = [];
        this.observeList = {};
    }

    addChange(cb) {
        this.changeCallbackList.push(cb);

        return this;
    }

    clearChange() {
        this.changeCallbackList = [];

        return this;
    }

    add(id, obj, doChange) {
        const idNum = parseInt(id, 10);
        for (let i = 0; i < this.list.length; i++) {
            if (idNum === this.list[i].id) {
                throw new Error('id重复');
            }
        }
        const data = { id: idNum };
        Object.keys(obj)
            .forEach((key) => {
                data[key] = obj[key];
            });
        this.list.push(data);
        this.list.push(obj);

        const e = {
            name: this.name,
            type: 'add',
            data,
        };

        if (doChange) {
            this.__change(e);
        }

        this.__actionObserve(e.data);

        return this;
    }

    addOrUpdate(id, obj, doChange) {
        let find = false;
        let data = null;
        const idNum = parseInt(id, 10);
        for (let i = 0; i < this.list.length; i++) {
            if (idNum === this.list[i].id) {
                Object.keys(obj)
                    .forEach((key) => {
                        this.list[i][key] = obj[key];
                    });
                data = this.list[i];
                find = true;
                break;
            }
        }

        if (!find) {
            data = { id: idNum };
            Object.keys(obj)
                .forEach((key) => {
                    data[key] = obj[key];
                });
            this.list.push(data);
        }

        const e = {
            name: this.name,
            type: 'addOrUpdate',
            data,
        };

        if (doChange) {
            this.__change(e);
        }

        this.__actionObserve(e.data);

        return this;
    }

    removeById(id, doChange) {
        const idNum = parseInt(id, 10);
        for (let i = 0; i < this.list.length; i++) {
            if (idNum === this.list[i].id) {
                const e = {
                    name: this.name,
                    type: 'remove',
                    data: this.list[i],
                };
                if (doChange) {
                    this.__change(e);
                }
                this.__actionObserve(e.data);
                this.list.splice(i, 1);
                break;
            }
        }

        return this;
    }

    updateById(id, obj, doChange) {
        const idNum = parseInt(id, 10);
        for (let i = 0; i < this.list.length; i++) {
            if (idNum === this.list[i].id) {
                Object.keys(obj)
                    .forEach((key) => {
                        const e = {
                            name: this.name,
                            type: 'update',
                            data: obj,
                        };
                        if (doChange) {
                            this.__change(e);
                        }
                        this.__actionObserve(e.data);
                        this.list[i][key] = obj[key];
                    });
                break;
            }
        }

        return this;
    }

    findById(id) {
        const idNum = parseInt(id, 10);
        for (let i = 0; i < this.list.length; i++) {
            if (idNum === this.list[i].id) {
                return this.list[i];
            }
        }

        return null;
    }

    // 根据事件更新
    action(event, doChange) {
        if (event.type === 'add') {
            const {
                data,
            } = event;
            this.add(data.id, data, doChange);
        } else if (event.type === 'update') {
            const {
                data,
            } = event;
            this.updateById(data.id, data, doChange);
        } else if (event.type === 'remove') {
            const {
                data,
            } = event;
            this.removeById(data.id, doChange);
        } else if (event.type === 'addOrUpdate') {
            const {
                data,
            } = event;
            this.addOrUpdate(data.id, data, doChange);
        }
    }

    addObserve(id, cb) {
        if (!this.observeList[id]) {
            this.observeList[id] = [];
        }

        this.observeList[id].push(cb);
    }

    __change(event) {
        console.log('change', this.list);
        this.changeCallbackList.forEach((cb) => {
            cb(event);
        });
    }

    __actionObserve(data) {
        console.log('__observe', this.list, data);
        const { id } = data;
        if (!this.observeList[id]) {
            return false;
        }
        this.observeList[id].forEach((cb) => {
            cb(data);
        });
        return true;
    }
}

module.exports = Collection;
